pub mod server;

extern crate reqwest;

use regex::Regex;
use scraper::{Html, Selector};

use server::metasearch;
use youtube_dl::{Error, YoutubeDl, YoutubeDlOutput};

use cursive::{
    traits::{Nameable, Resizable, Scrollable},
    views::{Dialog, EditView, LinearLayout, Panel, TextView},
};

fn main() -> Result<(), reqwest::Error> {
    // let url = match std::env::args().nth(1) {
    //     Some(url) => url,
    //     None => panic!("Вы не указали ссылку!"),
    // };

    // let _videos = extract_videos(&url)?;

    metasearch::spawn();

    let mut app = cursive::default();

    app.add_layer(
        Dialog::new()
            .content(
                LinearLayout::vertical()
                    .child(
                        EditView::new()
                            .on_submit(|s, text| {
                                s.call_on_name("results", |layout: &mut LinearLayout| {
                                    if text != "" {
                                        layout.clear();
                                        for res in search(text).unwrap().iter() {
                                            layout.add_child(Panel::new(TextView::new(res)));
                                        }
                                    }
                                });
                                s.call_on_name("search", |edit: &mut EditView| {
                                    edit.set_content("")
                                });
                            })
                            .with_name("search"),
                    )
                    .child(
                        LinearLayout::vertical()
                            .with_name("results")
                            .scrollable()
                            .fixed_height(10),
                    ),
            )
            .title("Поиск порно")
            .button("quit", |q| q.quit())
            .fixed_width(60),
    );

    app.run();

    Ok(())
}

fn search(text: &str) -> Result<Vec<String>, reqwest::Error> {
    let mut url = String::from("http://localhost:8000?query=");
    url.push_str(text);

    let res = reqwest::blocking::get(url)?;

    res.json()
}

fn extract_videos(url: &str) -> Result<Vec<String>, reqwest::Error> {
    let html = fetch_page(&url).unwrap();
    let mut videos = parse_videos(&html).unwrap();

    let ytdl_extracted = youtubedl_extract(&url).unwrap();

    if !ytdl_extracted.is_empty() {
        videos.push(ytdl_extracted);
    }

    Ok(videos)
}

fn youtubedl_extract(url: &str) -> Result<String, Error> {
    let video_obj = YoutubeDl::new(url).run();

    Ok(match video_obj {
        Ok(video) => match video {
            YoutubeDlOutput::SingleVideo(video) => video.url.ok_or(()).unwrap(),
            YoutubeDlOutput::Playlist(video) => video.webpage_url.ok_or(()).unwrap(),
        },
        Err(_) => String::from(""),
    })
}

fn parse_videos(html: &str) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut all_videos = vec![];

    let document = Html::parse_document(html);

    let mut videos: Vec<String> = document
        .select(&Selector::parse("video").unwrap())
        .map(|element| element.value().attr("src").unwrap())
        .filter(|element| !element.starts_with("blob:"))
        .map(|element| element.to_string())
        .collect();

    if videos.is_empty() {
        all_videos.append(&mut videos);
    }

    let re = Regex::new(r#"http[s]?:(//|\\/\\/).*\.(m3u8|mp4).*?['"]"#).unwrap();
    let html_tags = Regex::new(r"[><]").unwrap();

    let mut m3u8_videos: Vec<String> = re
        .find_iter(html)
        .map(|element| element.as_str().replace('"', "").replace('\'', ""))
        .filter(|element| !html_tags.is_match(element))
        .collect();

    all_videos.append(&mut m3u8_videos);

    Ok(all_videos.iter().map(|el| el.to_string()).collect())
}

fn fetch_page(url: &str) -> Result<String, reqwest::Error> {
    let res = reqwest::blocking::get(url)?;

    Ok(res.text().unwrap())
}
